package game.util;

import game.Constants;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Vector;

/**
 * Following the 5-Factor model of personality traits
 * 
 * @author churchmf
 * 
 */
public class TraitUtil {

	public abstract class Trait {
		public static final int NUM_TRAITS = 5;
		protected int value;

		public Trait(int value) {
			this.setValue(value);
		}

		public int getValue() {
			return value;
		}

		public void setValue(int value) {
			if (value <= Constants.TRAIT_MAX && value >= Constants.TRAIT_MIN) {
				this.value = value;
			} else
				Util.log("Trait unchanged due to limit\n");
		}

		private boolean hasAlot() {
			return this.value > Constants.TRAIT_LOT_MIN
					&& this.value <= Constants.TRAIT_LOT_MAX;
		}

		private boolean hasSome() {
			return this.value >= Constants.TRAIT_SOME_MIN
					&& this.value <= Constants.TRAIT_SOME_MAX;
		}

		private boolean hasLittle() {
			return this.value >= Constants.TRAIT_LITTLE_MIN
					&& this.value < Constants.TRAIT_LITTLE_MAX;
		}

		protected abstract List<String> getLittleNames();

		protected abstract List<String> getSomeNames();

		protected abstract List<String> getLotNames();

		public String getDescription() {
			final List<String> descriptions = new Vector<String>();
			if (this.hasAlot())
				descriptions.addAll(getLotNames());
			else if (this.hasSome())
				descriptions.addAll(getSomeNames());
			else if (this.hasLittle())
				descriptions.addAll(getLittleNames());

			String description = Util.GetRandomListValue(descriptions);
			if (description != null)
				return description;
			else
				throw new IllegalStateException("Null description generated");
		}

		public abstract List<String> getGreetings();

		public abstract List<String> getGreetingsReply();

		public String toString() {
			return "Trait [" + this.getDescription() + ", " + this.value + "]";
		}
	}

	// Appreciation for art, emotion, adventure, unusual ideas, curiosity, and
	// variety of experience.
	public class Openness extends Trait {

		public Openness(int value) {
			super(value);
		}

		@Override
		protected List<String> getLittleNames() {
			return Arrays.asList(Constants.OPENNESS_LITTLE_DESCRIPTION);
		}

		@Override
		protected List<String> getSomeNames() {
			return Arrays.asList(Constants.OPENNESS_SOME_DESCRIPTION);
		}

		@Override
		protected List<String> getLotNames() {
			return Arrays.asList(Constants.OPENNESS_LOT_DESCRIPTION);
		}

		@Override
		public List<String> getGreetings() {
			return Arrays.asList(Constants.OPENNESS_GREETINGS);
		}

		@Override
		public List<String> getGreetingsReply() {
			return Arrays.asList(Constants.OPENNESS_GREETINGS_REPLY);
		}
	}

	// A tendency to show self-discipline, act dutifully, and aim for
	// achievement; planned rather than spontaneous behavior.
	public class Conscientiousness extends Trait {

		public Conscientiousness(int value) {
			super(value);
		}

		@Override
		protected List<String> getLittleNames() {
			return Arrays
					.asList(Constants.CONSCIENTIOUSNESS_LITTLE_DESCRIPTION);
		}

		@Override
		protected List<String> getSomeNames() {
			return Arrays.asList(Constants.CONSCIENTIOUSNESS_SOME_DESCRIPTION);
		}

		@Override
		protected List<String> getLotNames() {
			return Arrays.asList(Constants.CONSCIENTIOUSNESS_LOT_DESCRIPTION);
		}

		@Override
		public List<String> getGreetings() {
			return Arrays.asList(Constants.CONSCIENTIOUSNESS_GREETINGS);
		}

		@Override
		public List<String> getGreetingsReply() {
			return Arrays.asList(Constants.CONSCIENTIOUSNESS_GREETINGS_REPLY);
		}
	}

	// Energy, positive emotions, surgency, and the tendency to seek stimulation
	// in the company of others.
	public class Extraversion extends Trait {

		public Extraversion(int value) {
			super(value);
		}

		@Override
		protected List<String> getLittleNames() {
			return Arrays.asList(Constants.EXTRAVERSION_LITTLE_DESCRIPTION);
		}

		@Override
		protected List<String> getSomeNames() {
			return Arrays.asList(Constants.EXTRAVERSION_SOME_DESCRIPTION);
		}

		@Override
		protected List<String> getLotNames() {
			return Arrays.asList(Constants.EXTRAVERSION_LOT_DESCRIPTION);
		}

		@Override
		public List<String> getGreetings() {
			return Arrays.asList(Constants.EXTRAVERSION_GREETINGS);
		}
		
		@Override
		public List<String> getGreetingsReply() {
			return Arrays.asList(Constants.EXTRAVERSION_GREETINGS_REPLY);
		}
	}

	// A tendency to be compassionate and cooperative rather than suspicious and
	// antagonistic towards others.
	public class Agreeableness extends Trait {

		public Agreeableness(int value) {
			super(value);
		}

		@Override
		protected List<String> getLittleNames() {
			return Arrays.asList(Constants.AGREEABLENESS_LITTLE_DESCRIPTION);
		}

		@Override
		protected List<String> getSomeNames() {
			return Arrays.asList(Constants.AGREEABLENESS_SOME_DESCRIPTION);
		}

		@Override
		protected List<String> getLotNames() {
			return Arrays.asList(Constants.AGREEABLENESS_LOT_DESCRIPTION);
		}

		@Override
		public List<String> getGreetings() {
			return Arrays.asList(Constants.AGREEABLENESS_GREETINGS);
		}
		
		@Override
		public List<String> getGreetingsReply() {
			return Arrays.asList(Constants.AGREEABLENESS_GREETINGS_REPLY);
		}
	}

	// A tendency to experience unpleasant emotions easily, such as anger,
	// anxiety, depression, or vulnerability.
	public class Neuroticism extends Trait {

		public Neuroticism(int value) {
			super(value);
		}

		@Override
		protected List<String> getLittleNames() {
			return Arrays.asList(Constants.NEUROTICISM_LITTLE_DESCRIPTION);
		}

		@Override
		protected List<String> getSomeNames() {
			return Arrays.asList(Constants.NEUROTICISM_SOME_DESCRIPTION);
		}

		@Override
		protected List<String> getLotNames() {
			return Arrays.asList(Constants.NEUROTICISM_LOT_DESCRIPTION);
		}

		@Override
		public List<String> getGreetings() {
			return Arrays.asList(Constants.NEUROTICISM_GREETINGS);
		}
		
		@Override
		public List<String> getGreetingsReply() {
			return Arrays.asList(Constants.NEUROTICISM_GREETINGS_REPLY);
		}
	}

	public Collection<Trait> getRandomTraits() {
		final Collection<Trait> traits = new Vector<Trait>(Trait.NUM_TRAITS);
		traits.add(new Openness(Util.GetRandomIntBetween(Constants.TRAIT_MIN,
				Constants.TRAIT_MAX)));
		traits.add(new Conscientiousness(Util.GetRandomIntBetween(
				Constants.TRAIT_MIN, Constants.TRAIT_MAX)));
		traits.add(new Extraversion(Util.GetRandomIntBetween(
				Constants.TRAIT_MIN, Constants.TRAIT_MAX)));
		traits.add(new Agreeableness(Util.GetRandomIntBetween(
				Constants.TRAIT_MIN, Constants.TRAIT_MAX)));
		traits.add(new Neuroticism(Util.GetRandomIntBetween(
				Constants.TRAIT_MIN, Constants.TRAIT_MAX)));
		return traits;
	}

	public Collection<Trait> getEmptyTraits() {
		final Collection<Trait> traits = new Vector<Trait>(Trait.NUM_TRAITS);
		traits.add(new Openness(Constants.TRAIT_MIN));
		traits.add(new Conscientiousness(Constants.TRAIT_MIN));
		traits.add(new Extraversion(Constants.TRAIT_MIN));
		traits.add(new Agreeableness(Constants.TRAIT_MIN));
		traits.add(new Neuroticism(Constants.TRAIT_MIN));
		return traits;
	}

	public static Openness getOpenness(Collection<Trait> traits) {
		for (Trait trait : traits) {
			if (trait instanceof Openness)
				return (Openness) trait;
		}
		throw new IllegalStateException("Openness not found");
	}

	public static Conscientiousness getConscientiousness(
			Collection<Trait> traits) {
		for (Trait trait : traits) {
			if (trait instanceof Conscientiousness)
				return (Conscientiousness) trait;
		}
		throw new IllegalStateException("Conscientiousness not found");
	}

	public static Extraversion getExtraversion(Collection<Trait> traits) {
		for (Trait trait : traits) {
			if (trait instanceof Extraversion)
				return (Extraversion) trait;
		}
		throw new IllegalStateException("Extraversion not found");
	}

	public static Agreeableness getAgreeableness(Collection<Trait> traits) {
		for (Trait trait : traits) {
			if (trait instanceof Agreeableness)
				return (Agreeableness) trait;
		}
		throw new IllegalStateException("Agreeableness not found");
	}

	public static Neuroticism getNeuroticism(Collection<Trait> traits) {
		for (Trait trait : traits) {
			if (trait instanceof Neuroticism)
				return (Neuroticism) trait;
		}
		throw new IllegalStateException("Neuroticism not found");
	}
}
